﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.ComponentModel;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using TencentCloud.Scf.V20180416.Models;
using ZenSystemService.Api.Data;
using ZenSystemService.Api.DTOs;
using ZenSystemService.Api.Entities;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace ZenSystemService.Api.Services
{
    public class InstitutionSalesOrderService
    {
        private readonly ApplicationDbContext _context;
        private IMapper _mapper;
        public InstitutionSalesOrderService(ApplicationDbContext context,IMapper mapper)
        {
            _context = context;
            _mapper = mapper;
        }

        public async Task<IEnumerable<InstitutionSalesOrderDTO>> GetAllInstitutionSalesOrdersAsync(ReceiveObject req)
        {
            string orderBy = req.Order;
            var splited = orderBy.Split(' ');
            var orderField = "";
            var orderMethod = "";
            if (splited.Length > 0)
            {
                orderField = $"{splited[0]}";
            }
            if (splited.Length > 1)
            {
                orderMethod = splited[1];
            }
                
            var orders = _context.InstitutionSalesOrders.Include(o => o.OrderItems)
                .ThenInclude(oi => oi.ProductType).ThenInclude(pd => pd.DeviceType)
                        .Include(o => o.User).ThenInclude(u => u.Institution).AsQueryable();
            if (!string.IsNullOrEmpty(req.Where))
            {
                var criterias = req.Where.Split('&');
                foreach (var criteria in criterias)
                {
                    var criteriaPair = criteria.Split('=');
                    var parameter = Expression.Parameter(typeof(InstitutionSalesOrder), "x");
                    var property = Expression.Property(parameter, criteriaPair[0]);
                    var fieldType = typeof(InstitutionSalesOrder).GetProperty(criteriaPair[0])
                        .PropertyType;
                    var fieldValue = ConvertValueToFieldType(criteriaPair[1], fieldType);
                    var valueConstant = Expression.Constant(fieldValue);

                    // 创建比较表达式，例如: x => x.PropertyName == value
                    var predicate = Expression.Lambda<Func<InstitutionSalesOrder, bool>>(
                        Expression.Equal(property, valueConstant),
                        parameter
                    );

                    orders = orders.Where(predicate);
                }
                if (!string.IsNullOrEmpty(orderBy))
                    orders = orders.OrderBy(orderField);
                int index = (req.Page - 1 < 0 ? 0 : req.Page - 1) * req.PageSize;
                orders = orders.Skip(index).Take(req.PageSize)
                        ;           
            }
            return _mapper.Map<IEnumerable<InstitutionSalesOrderDTO>>(orders.ToList());
        }

        private static object ConvertValueToFieldType(object value, Type fieldType)
        {
            // 如果字段类型为null，或者值已经是正确的类型，则直接返回值
            if (fieldType == null || fieldType.IsInstanceOfType(value))
            {
                return value;
            }

            try
            {
                // 使用TypeDescriptor.GetConverter来获取相应的类型转换器
                var converter = TypeDescriptor.GetConverter(fieldType);
                if (converter != null && converter.CanConvertFrom(value.GetType()))
                {
                    return converter.ConvertFrom(value);
                }
            }
            catch
            {
                // 转换失败时的处理逻辑...
            }

            // 如果没有找到合适的转换器，或者转换失败，可以返回null或者抛出异常
            return null;
        }
        public async Task<IEnumerable<InstitutionSalesOrderDTO>> GetAllInstitutionSalesOrderMastersAsync(ReceiveObject req)
        {
            string orderBy = req.Order;
            var splited = orderBy.Split(' ');
            var orderField = "";
            var orderMethod = "";
            if(splited.Length > 0)
            {
                orderField = splited[0];
            }
            if(splited.Length > 1)
            {
                orderMethod = splited[1];
            }

            if (!string.IsNullOrEmpty(orderBy))
            {
                int index = (req.Page - 1 < 0 ? 0 : req.Page - 1) * req.PageSize;
                var orders = await _context.InstitutionSalesOrders.OrderBy(orderField).Skip(index).Take(req.PageSize).ToListAsync();
                return _mapper.Map<IEnumerable<InstitutionSalesOrderDTO>>(orders);
            }
            else
            {
                var orders = await _context.InstitutionSalesOrders.ToListAsync();
                return _mapper.Map<IEnumerable<InstitutionSalesOrderDTO>>(orders);
            }
        }

        public async Task<InstitutionSalesOrderDTO?> GetInstitutionSalesOrderByIdAsync(int id)
        {
            var order = await _context.InstitutionSalesOrders.Where(o => o.Id == id)
                .Include(o => o.OrderItems).ThenInclude(i => i.ProductType).ThenInclude(p => p.DeviceType)
                .Include(o => o.Institution)
                .SingleOrDefaultAsync();
            if(order != null)
                return _mapper.Map<InstitutionSalesOrderDTO>(order);
            return null;
        }

        public async Task<InstitutionSalesOrderDTO> CreateInstitutionSalesOrderAsync(InstitutionSalesOrderDTO institutionSalesOrder)
        {
            var orderEntity = _mapper.Map<InstitutionSalesOrder>(institutionSalesOrder);
            
            if (institutionSalesOrder.Id > 0)
            {
                await UpdateInstitutionSalesOrderAsync(orderEntity);
                var user = _context.Users.SingleOrDefault(u => u.UserId == institutionSalesOrder.User.UserId);
                orderEntity.User = user;
            }
            else
            {
                var user = _context.Users.First(u => u.UserId == institutionSalesOrder.User.UserId);
                orderEntity.User = user;
                var intitution = _context.Institutions.First(i => i.InstitutionId == institutionSalesOrder.Institution.InstitutionId);
                orderEntity.Institution = intitution;
                orderEntity.CreatedDate = DateTime.Now;
                await _context.InstitutionSalesOrders.AddAsync(orderEntity);
                await _context.SaveChangesAsync();
            }
            return _mapper.Map<InstitutionSalesOrderDTO>(orderEntity);
        }

        public async Task<bool> UpdateInstitutionSalesOrderAsync(InstitutionSalesOrder institutionSalesOrder)
        {
            var institution = await _context.Institutions.FirstAsync(i => i.InstitutionId == institutionSalesOrder.Institution.InstitutionId);
            institutionSalesOrder.Institution = institution;
            var existedItems = _context.InstitutionSalesOrderItems.Where(i => i.InstitutionSalesOrderId == institutionSalesOrder.Id);
            _context.InstitutionSalesOrderItems.RemoveRange(existedItems);
            _context.SaveChanges();
            
            await _context.SaveChangesAsync();
            foreach(var item in institutionSalesOrder.OrderItems)
            {
                _context.Entry(item).State = EntityState.Added;
            }
            _context.Entry(institutionSalesOrder).State = EntityState.Modified;
            int count=await _context.SaveChangesAsync();
            return count > 0 ? true : false;
        }

        public async Task<InstitutionSalesOrder> UpdateInstitutionSalesOrderStatusAsync(int orderId, int newStatus)
        {
            var order = _context.InstitutionSalesOrders.Include(o => o.OrderItems)
                .ThenInclude(oi => oi.ProductType)
                .FirstOrDefault(o => o.Id == orderId);
            if (order == null)
                return null;
            order.Status = newStatus;
            _context.Entry(order).State = EntityState.Modified;
            if (newStatus == 1)
            {
                await CreateProductsAsync(order);
                await CreateTrainingItemsAsync(order);
            }
            else
                await RemoveProductsAsync(order);
            await _context.SaveChangesAsync();
            return order; 
        }

        /// <summary>
        /// 根据订单生成机构产品, 产品明细里面的每一个ProductType对应一条记录
        /// 如果是修改订单状态，把已付款改成未付款，需要把之前生成的Product删除掉
        /// </summary>
        /// <param name="product"></param>
        /// <returns></returns>
        private async Task<IEnumerable<Product>> CreateProductsAsync(InstitutionSalesOrder salesOrder)
        {
            var products = new List<Product>();
            //订单状态从已付款改成未付款，应该把已付款时候生成的产品删掉
            if (salesOrder.Status == 0)
            {
                var existedProducts = _context.Products.Where(p => p.InstitutionSalesOrderId == salesOrder.Id
                    && p.InstitutionId == salesOrder.InstitutionId);
                _context.Products.RemoveRange(existedProducts);
            }
            else
            {
                foreach (var item in salesOrder.OrderItems)
                {
                    for (int i = 0; i < item.Quantity; i++)
                    {
                        var product = new Product
                        {
                            Name = item.ProductType.Name,
                            InstitutionSalesOrderId = salesOrder.Id,
                            ProductTypeId = item.ProductTypeId,
                            InstitutionId = salesOrder.InstitutionId,
                            EffectiveStartDate = DateTime.Now.AddDays(3),
                            ValidityDays = item.ValidityDays,
                            UniqueNumber = Guid.NewGuid().ToString(),
                            Enabled = "1"
                        };
                        products.Add(product);
                    }
                }
                await _context.Products.AddRangeAsync(products);
                await _context.SaveChangesAsync();
            }
            return products;
        }

        /// <summary>
        /// 如果订单被标记为未付款，应该把这个订单相关的产品标记为不可用
        /// </summary>
        /// <param name="salesOrder"></param>
        private async Task RemoveProductsAsync(InstitutionSalesOrder salesOrder)
        {            
            var products = _context.Products.Where(p => p.InstitutionSalesOrderId == salesOrder.Id);
            products.ToList().ForEach(p => p.Enabled = "0");
            _context.Products.UpdateRange(products);
            await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 付款后自动生成机构训练项目
        /// </summary>
        /// <param name="salesOrder"></param>
        /// <returns></returns>
        private async Task<IEnumerable<TrainingItem>> CreateTrainingItemsAsync(InstitutionSalesOrder salesOrder)
        {
            var existedTrainingItemNames = _context.TrainingItems.Where(
                ti => ti.InstitutionId == salesOrder.InstitutionId).Select(ti => ti.Name).ToList();
            var trainingItems = new List<TrainingItem>();
            foreach(var item in salesOrder.OrderItems)
            {
                var trainingItem = new TrainingItem
                {
                    Name = item.ProductType.Alias,
                    ProductTypeId = item.ProductTypeId,
                    InstitutionId = salesOrder.InstitutionId,
                    DeviceTypeId = item.ProductType.DeviceTypeId,
                };
                if(!existedTrainingItemNames.Contains(trainingItem.Name))
                    trainingItems.Add(trainingItem);
            }
            
            await _context.TrainingItems.AddRangeAsync(trainingItems);
            await _context.SaveChangesAsync();
            return trainingItems;
        }


        public async Task<bool> DeleteInstitutionSalesOrderAsync(int id)
        {
            var institutionSalesOrder = await _context.InstitutionSalesOrders.FindAsync(id);
            if (institutionSalesOrder != null)
            {
                _context.InstitutionSalesOrders.Remove(institutionSalesOrder);
                int count = await _context.SaveChangesAsync();
                return count > 0 ? true : false;
            }
            else
            {
                return false;
            }
        }
    }
}